import axios from 'axios';
import * as FormData from 'form-data';
import * as fs from 'fs';
import * as path from 'path';
import * as pinyin from 'pinyin';
import { createConnection } from 'typeorm';
import {
  User,
  Standard,
  EquipmentModel,
  EquipmentInstance,
  Script,
  TaskGroup,
  TaskGroupEquipmentInfo,
  TaskModel,
  TaskInstance,
} from './entity/Entities';

function saveFile(file: string): Promise<any> {
  const form = new FormData();
  form.append('file', fs.createReadStream(file));
  return axios.post(process.env.FILE_SERVICE_ENDPOINT, form, {
    headers: { ...form.getHeaders(), 'Access-Control-Allow-Origin': '*' },
  });
}

//no delete, only add or update
function updateEquipmentModel() {
  createConnection()
    .then(async (connection) => {
      //EquipmentModel
      // get all
      const equipmetnModelService = connection.getRepository(EquipmentModel);
      const taskModelService = connection.getRepository(TaskModel);
      const scriptService = connection.getRepository(Script);
      const standardService = connection.getRepository(Standard);
      const userService = connection.getRepository(User);
      // iterate dir
      const baseDir = path.resolve('ModelConfigs');
      const files = await fs.promises.readdir(baseDir);
      async function addScriptFile(
        scopeID: number,
        scopeType: string,
        scriptFilePath: string,
      ) {
        const filename = path.basename(scriptFilePath);
        const scriptName = filename.replace('.js', '');

        const code = await fs.promises.readFile(scriptFilePath, {
          encoding: 'utf-8',
        });
        let script = await scriptService.findOne({
          scopeID,
          scopeType,
          ename: scriptName,
        });
        if (script) {
          script.code = code;
        } else {
          script = {
            ename: scriptName,
            code,
            scopeID,
            scopeType,
            id: undefined,
          };
        }
        await scriptService.save(script);
      }
      async function addTaskModelDir(
        equipmentModelID: number,
        taskModelPath: string,
      ) {
        const taskName = path.basename(taskModelPath);
        const stats = await fs.promises.stat(taskModelPath);
        if (!stats.isDirectory()) return;
        let taskModel = await taskModelService.findOne({
          equipmentModelID: equipmentModelID,
          name: taskName,
        });
        const amisSchemaFileName = path.resolve(
          taskModelPath,
          'amisSchema.json',
        );
        let amisSchema = {};
        if (fs.existsSync(amisSchemaFileName)) {
          const content = await fs.promises.readFile(amisSchemaFileName, {
            encoding: 'utf-8',
          });
          amisSchema = JSON.parse(content);
        }
        const reportTemplatePath = path.resolve(
          taskModelPath,
          'reportTemplate.docx',
        );
        const res = await saveFile(reportTemplatePath);
        const reportTemplate = res.data.md5;
        if (taskModel) {
          taskModel.amisSchema = amisSchema;
          taskModel.reportTemplate = reportTemplate;
        } else {
          taskModel = {
            amisSchema,
            reportTemplate,
            equipmentModelID,
            name: taskName,
            //undefined
            id: undefined,
          };
        }
        await taskModelService.save(taskModel);

        const files = await fs.promises.readdir(taskModelPath, {
          withFileTypes: true,
        });

        for (const file of files) {
          if (file.isFile() && file.name.endsWith('.js')) {
            const scriptFilePath = path.resolve(taskModelPath, file.name);
            await addScriptFile(taskModel.id, 'taskModel', scriptFilePath);
          }
        }
      }
      async function addEquipmentModelDir(
        parentID: number,
        equipmentModelPath: string,
      ) {
        const baseName = path.basename(equipmentModelPath);
        const stats = await fs.promises.stat(equipmentModelPath);
        if (!stats.isDirectory()) return;

        const equipmentModelConfigFileNames = [
          'infoSchema.json',
          'taskSchema.json',
          'metaData.json',
          'coverTemplate.docx',
        ];
        const infoSchemaFileName = path.resolve(
          equipmentModelPath,
          'infoSchema.json',
        );
        let infoSchema = {};
        if (fs.existsSync(infoSchemaFileName)) {
          const content = await fs.promises.readFile(infoSchemaFileName, {
            encoding: 'utf-8',
          });
          infoSchema = JSON.parse(content);
        }

        let taskSchema = {};
        const taskSchemaFileName = path.resolve(
          equipmentModelPath,
          'taskSchema.json',
        );
        if (fs.existsSync(taskSchemaFileName)) {
          const content = await fs.promises.readFile(taskSchemaFileName, {
            encoding: 'utf-8',
          });
          taskSchema = JSON.parse(content);
        }
        const ename = pinyin(baseName, {
          style: pinyin.STYLE_NORMAL,
          segment: true,
          heteronym: false,
        }).join('');
        let metaData = {
          isUnique: false,
          ename,
          listLabels: [],
        };
        const metadataFileName = path.resolve(
          equipmentModelPath,
          'metaData.json',
        );
        if (fs.existsSync(metadataFileName)) {
          const metaDataContent = await fs.promises.readFile(metadataFileName, {
            encoding: 'utf-8',
          });
          metaData = { ...metaData, ...JSON.parse(metaDataContent) };
        }

        const coverTemplatePath = path.resolve(
          equipmentModelPath,
          'coverTemplate.docx',
        );
        let coverTemplate: string = '';
        // cover template
        if (fs.existsSync(coverTemplatePath)) {
          const res = await saveFile(coverTemplatePath);
          coverTemplate = res.data.md5;
        }

        // check exist
        let equipmentModel = await equipmetnModelService.findOne({
          parentID,
          name: baseName,
        });
        // update config if exist
        if (equipmentModel) {
          equipmentModel = {
            ...equipmentModel,
            infoSchema,
            taskSchema,
            metaData,
            coverTemplate,
          };
        } else {
          // insert config if not exist
          equipmentModel = {
            parentID,
            name: baseName,
            infoSchema,
            taskSchema,
            metaData,
            coverTemplate,
          };
        }
        await equipmetnModelService.save(equipmentModel);

        const files = await fs.promises.readdir(equipmentModelPath, {
          withFileTypes: true,
        });

        for (const file of files) {
          if (file.isFile() && file.name.endsWith('.js')) {
            const scriptFilePath = path.resolve(equipmentModelPath, file.name);
            await addScriptFile(
              equipmentModel.id,
              'equipmentModel',
              scriptFilePath,
            );
          }
        }

        const tasksPath = path.resolve(equipmentModelPath, 'tasks');
        // add TaskModel
        if (fs.existsSync(tasksPath) && fs.lstatSync(tasksPath).isDirectory()) {
          const files = await fs.promises.readdir(tasksPath, {
            withFileTypes: true,
          });
          for (const file of files) {
            const taskModelPath = path.join(tasksPath, file.name);
            if (file.isDirectory()) {
              await addTaskModelDir(equipmentModel.id, taskModelPath);
            }
          }
        }

        const subDirs = await fs.promises.readdir(equipmentModelPath, {
          withFileTypes: true,
        });
        for (const file of subDirs) {
          if (file.isDirectory() && file.name !== 'tasks') {
            await addEquipmentModelDir(
              equipmentModel.id,
              path.resolve(equipmentModelPath, file.name),
            );
          }
        }
      }
      for (const file of files) {
        const equipmentModelPath = path.join(baseDir, file);
        await addEquipmentModelDir(-1, equipmentModelPath);
      }
      const standards = await standardService.find();

      if (standards.length === 0) {
        await standardService.save([
          {
            name: '国标-2012',
          },
          {
            name: '行标-2018',
          },
        ]);
      }
      const users = await userService.find();
      if (users.length === 0) {
        await userService.save([
          {
            username: 'admin',
            password: 'admin',
            pwdHash: '',
          },
        ]);
      }
      connection.close();
    })
    .catch((error) => {
      console.error(
        '🚀 ~ file: index.ts ~ line 273 ~ updateEquipmentModel ~ error',
        error,
      );
    });
}
updateEquipmentModel();
